package com.yoooya.base.admin.shiro;

import com.yoooya.base.commons.CommonUtils;
import com.yoooya.base.model.po.system.SysMenuPo;
import com.yoooya.base.model.po.system.UserInfoPo;
import com.yoooya.base.model.qo.system.SysRoleMenuQo;
import com.yoooya.base.model.qo.system.UserInfoQo;
import com.yoooya.base.service.system.SysMenuService;
import com.yoooya.base.service.system.SysRoleMenuService;
import com.yoooya.base.service.system.UserInfoService;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * 
 * @Desc: 自定义Realm
 * @author Mr Du
 * @createTime 2018年2月25日
 * @version: v1.0
 */
@Component
public class CustomRealm extends AuthorizingRealm {
	@Autowired
	private UserInfoService userInfoService;
	@Autowired
	private SysMenuService sysMenuService;

	
	private static Logger logger=LoggerFactory.getLogger(CustomRealm.class);

	public CustomRealm() {
		logger.info("CustomRealm====================");
	}


	@Override
	public String getName() {
		return "CustomRealm";
	}

	@Bean(name = "credentialsMatcher")
	public HashedCredentialsMatcher credentialsMatcher(){
		HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
		credentialsMatcher.setHashAlgorithmName("md5");
		credentialsMatcher.setHashIterations(1);
		return credentialsMatcher;
	}

	@Override
	public void setCredentialsMatcher(@Qualifier("credentialsMatcher")CredentialsMatcher credentialsMatcher){
		super.setCredentialsMatcher(credentialsMatcher);
	}

	/**
	 * realm授权方法 从输入参数principalCollection得到身份信息 根据身份信息到数据库查找权限信息 将权限信息添加给授权信息对象
	 * 返回 授权信息对象(判断用户访问url是否在权限信息中没有体现)
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		UserInfoPo user = (UserInfoPo) principalCollection.getPrimaryPrincipal();

		String roleIds = user.getRoleIds();
		List<String> btnList = null;
		try{
			btnList = sysMenuService.queryBtnsByRoles(roleIds);
		}catch (Exception e){
			e.printStackTrace();
		}
		// 用户权限列表
		Set<String> permsSet = new HashSet<String>();
		if(btnList!=null && btnList.size()>0){
			permsSet.addAll(btnList);
		}
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.setStringPermissions(permsSet);
		return info;
	}

	/**
	 * 表单认证过滤器认证时会调用自定义Realm的认证方法进行认证，成功回到index.do，再跳转到index.jsp页面
	 *
	 * 前提：表单认证过滤器收集和组织用户名和密码信息封装为token对象传递给此方法
	 *
	 * token:封装了身份信息和凭证信息 2步骤：比对身份 信息；比对凭证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		String username = (String) token.getPrincipal();
		String password = new String((char[]) token.getCredentials());

		// 查询用户信息
		UserInfoQo tbAdminQo = new UserInfoQo();
		tbAdminQo.setUserName(username);
		List<UserInfoPo> admins = null;
		UserInfoPo userInfoPo = null;
		try{
			admins = this.userInfoService.query(tbAdminQo);
			if(admins!=null && admins.size()>0){
				userInfoPo = admins.get(0);
			}
		}catch (Exception e){
			e.printStackTrace();
		}

		// 账号不存在
		if (userInfoPo == null ) {
			throw new UnknownAccountException("账号不存在!");
		}
		// 密码错误
		if (!password.equals(userInfoPo.getPassword())) {
			throw new IncorrectCredentialsException("账号或密码不正确!");
		}

		// 账号未分配角色
		if (userInfoPo.getRoleIds() == null ) {
			throw new UnknownAccountException("账号未分配角色!");
		}

		//cjianquan 2020/2/8 登录成功，查询菜单
		try{
			List<SysMenuPo> menuList = this.sysMenuService.queryByRoles(userInfoPo.getRoleIds());
			userInfoPo.setMenuList(menuList);
		}catch (Exception e){
			e.printStackTrace();
		}
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userInfoPo, password, getName());
		return info;
	}
}
